/*-------------------------------------------------------------------------
Parser.cs -- Recursive Descent Parser
Compiler Generator Coco/R,
Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
extended by M. Loeberbauer & A. Woess, Univ. of Linz
extended (June 2004) by Pat Terry, Rhodes University (p.terry@ru.ac.za)
(changes marked as "pdt")

This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

As an exception, it is allowed to write an extension of Coco/R that is
used as a plugin in non-free software.

If not otherwise stated, any source code generated by Coco/R (other than
Coco/R itself) does not fall under the GNU General Public License.
-------------------------------------------------------------------------*/
using System.Collections;

using System;
using System.IO;
using System.Text;

namespace at.jku.ssw.Coco {

public class Parser {
	const int _EOF = 0;
	const int _ident = 1;
	const int _number = 2;
	const int _string = 3;
	const int _badString = 4;
	const int maxT = 44;
	const int _ddtSym = 45;

	const bool T = true;
	const bool x = false;
	const int minErrDist = 2;

	public static Token token;    // last recognized token   /* pdt */
	public static Token la;       // lookahead token
	static int errDist = minErrDist;

	const int id = 0;
	const int str = 1;

	static bool genScanner;
	static string tokenString;         // used in declarations of literal tokens
	static string noString = "-none-"; // used in declarations of literal tokens

/*-------------------------------------------------------------------------*/



	static void SynErr (int n) {
		if (errDist >= minErrDist) Errors.SynErr(la.line, la.col, n);
		errDist = 0;
	}

	public static void SemErr (string msg) {
		if (errDist >= minErrDist) Errors.Error(token.line, token.col, msg); /* pdt */
		errDist = 0;
	}

	public static void SemError (string msg) {
		if (errDist >= minErrDist) Errors.Error(token.line, token.col, msg); /* pdt */
		errDist = 0;
	}

	public static void Warning (string msg) { /* pdt */
		if (errDist >= minErrDist) Errors.Warn(token.line, token.col, msg);
		errDist = 0;
	}

	public static bool Successful() { /* pdt */
		return Errors.count == 0;
	}

	public static string LexString() { /* pdt */
		return token.val;
	}

	public static string LookAheadString() { /* pdt */
		return la.val;
	}

	static void Get () {
		for (;;) {
			token = la; /* pdt */
			la = Scanner.Scan();
			if (la.kind <= maxT) { ++errDist; break; }
				if (la.kind == 45) {
				Tab.SetDDT(la.val);
				}

			la = token; /* pdt */
		}
	}

	static void Expect (int n) {
		if (la.kind==n) Get(); else { SynErr(n); }
	}

	static bool StartOf (int s) {
		return set[s, la.kind];
	}

	static void ExpectWeak (int n, int follow) {
		if (la.kind == n) Get();
		else {
			SynErr(n);
			while (!StartOf(follow)) Get();
		}
	}

	static bool WeakSeparator (int n, int syFol, int repFol) {
		bool[] s = new bool[maxT+1];
		if (la.kind == n) { Get(); return true; }
		else if (StartOf(repFol)) return false;
		else {
			for (int i=0; i <= maxT; i++) {
				s[i] = set[syFol, i] || set[repFol, i] || set[0, i];
			}
			SynErr(n);
			while (!s[la.kind]) Get();
			return StartOf(syFol);
		}
	}

	static void Coco() {
		Symbol sym; Graph g, g1, g2; string gramName; BitArray s;
		if (la.kind == 42) {
			UsingDecl(out ParserGen.usingPos);
		}
		Expect(5);
		genScanner = true;
		Tab.ignored = new BitArray(CharClass.charSetSize);
		Expect(1);
		gramName = token.val;
		int beg = la.pos;
		while (StartOf(1)) {
			Get();
		}
		Tab.semDeclPos = new Position(beg, la.pos-beg, 0);
		if (la.kind == 6) {
			Get();
			DFA.ignoreCase = true;
		}
		if (la.kind == 7) {
			Get();
			while (la.kind == 1) {
				SetDecl();
			}
		}
		if (la.kind == 8) {
			Get();
			while (la.kind == 1 || la.kind == 3) {
				TokenDecl(Node.t);
			}
		}
		if (la.kind == 9) {
			Get();
			while (la.kind == 1) {
				NameDecl();
			}
		}
		if (la.kind == 10) {
			Get();
			while (la.kind == 1 || la.kind == 3) {
				TokenDecl(Node.pr);
			}
		}
		while (la.kind == 11) {
			Get();
			bool nested = false;
			Expect(12);
			TokenExpr(out g1);
			Expect(13);
			TokenExpr(out g2);
			if (la.kind == 14) {
				Get();
				nested = true;
			}
			new Comment(g1.l, g2.l, nested);
		}
		while (la.kind == 15) {
			Get();
			Set(out s);
			Tab.ignored.Or(s);
		}
		while (!(la.kind == 0 || la.kind == 16)) {SynErr(45); Get();}
		Expect(16);
		if (genScanner) DFA.MakeDeterministic();
		Graph.DeleteNodes();
		while (la.kind == 1) {
			Get();
			sym = Symbol.Find(token.val);
			bool undef = sym == null;
			if (undef) sym = new Symbol(Node.nt, token.val, token.line);
			else {
			  if (sym.typ == Node.nt) {
			    if (sym.graph != null) SemErr("name declared twice");
			  } else SemErr("this symbol kind not allowed on left side of production");
			  sym.line = token.line;
			}
			bool noAttrs = sym.attrPos == null;
			sym.attrPos = null;
			if (la.kind == 27 || la.kind == 29) {
				AttrDecl(sym);
			}
			if (!undef)
			  if (noAttrs != (sym.attrPos == null))
			    SemErr("attribute mismatch between declaration and use of this symbol");
			if (la.kind == 40) {
				SemText(out sym.semPos);
			}
			ExpectWeak(17, 2);
			Expression(out g);
			sym.graph = g.l;
			Graph.Finish(g);
			ExpectWeak(18, 3);
		}
		Expect(19);
		Expect(1);
		if (gramName != token.val)
		  SemErr("name does not match grammar name");
		Tab.gramSy = Symbol.Find(gramName);
		if (Tab.gramSy == null)
		  SemErr("missing production for grammar name");
		else {
		  sym = Tab.gramSy;
		  if (sym.attrPos != null)
		    SemErr("grammar symbol must not have attributes");
		}
		Tab.noSym = new Symbol(Node.t, "???", 0); // noSym gets highest number
		Tab.SetupAnys();
		Tab.RenumberPragmas();
		if (Tab.ddt[2]) Node.PrintNodes();
		if (Errors.count == 0) {
		  Console.WriteLine("checking");
		  Tab.CompSymbolSets();
		  if (Tab.ddt[7]) Tab.XRef();
		  if (Tab.GrammarOk()) {
		    if (!Tab.ddt[9]) {
		      Console.Write("parser");
		      ParserGen.WriteParser(Tab.ddt[10]);
		      if (genScanner) {
		        Console.Write(" + scanner");
		        DFA.WriteScanner(Tab.ddt[10]);
		        if (Tab.ddt[0]) DFA.PrintStates();
		      }
		      if (Tab.ddt[11]) {
		        Console.Write(" + driver");
		        DriverGen.WriteDriver();
		      }
		      Console.WriteLine(" generated");
		    }
		    if (Tab.ddt[8]) ParserGen.WriteStatistics();
		  }
		}
		if (Tab.ddt[6]) Tab.PrintSymbolTable();
		Expect(18);
	}

	static void UsingDecl(out Position pos) {
		Expect(42);
		int beg = token.pos;
		while (StartOf(4)) {
			Get();
		}
		Expect(43);
		int end = token.pos;
		while (la.kind == 42) {
			Get();
			while (StartOf(4)) {
				Get();
			}
			Expect(43);
			end = token.pos;
		}
		pos = new Position(beg, end - beg + 1, 0);
	}

	static void SetDecl() {
		BitArray s;
		Expect(1);
		string name = token.val;
		CharClass c = CharClass.Find(name);
		if (c != null) SemErr("name declared twice");
		Expect(17);
		Set(out s);
		if (Sets.Elements(s) == 0) SemErr("character set must not be empty");
		c = new CharClass(name, s);
		Expect(18);
	}

	static void TokenDecl(int typ) {
		string name; int kind; Symbol sym; Graph g;
		Sym(out name, out kind);
		sym = Symbol.Find(name);
		if (sym != null) SemErr("name declared twice");
		else {
		  sym = new Symbol(typ, name, token.line);
		  sym.tokenKind = Symbol.fixedToken;
		}
		tokenString = null;
		while (!(StartOf(5))) {SynErr(46); Get();}
		if (la.kind == 17) {
			Get();
			TokenExpr(out g);
			Expect(18);
			if (kind == str) SemErr("a literal must not be declared with a structure");
			Graph.Finish(g);
			if (tokenString == null || tokenString.Equals(noString))
			  DFA.ConvertToStates(g.l, sym);
			else { // TokenExpr is a single string
			  if (Tab.literals[tokenString] != null)
			    SemErr("token string declared twice");
			  Tab.literals[tokenString] = sym;
			  DFA.MatchLiteral(tokenString, sym);
			}
		} else if (StartOf(6)) {
			if (kind == id) genScanner = false;
			else DFA.MatchLiteral(sym.name, sym);
		} else SynErr(47);
		if (la.kind == 40) {
			SemText(out sym.semPos);
			if (typ != Node.pr) SemErr("semantic action not allowed here");
		}
	}

	static void NameDecl() {
		string alias;
		Expect(1);
		alias = token.val;
		Expect(17);
		if (la.kind == 1) {
			Get();
		} else if (la.kind == 3) {
			Get();
		} else SynErr(48);
		Tab.NewName(alias, token.val);
		Expect(18);
	}

	static void TokenExpr(out Graph g) {
		Graph g2;
		TokenTerm(out g);
		bool first = true;
		while (WeakSeparator(31, 7, 8)) {
			TokenTerm(out g2);
			if (first) { Graph.MakeFirstAlt(g); first = false; }
			Graph.MakeAlternative(g, g2);
		}
	}

	static void Set(out BitArray s) {
		BitArray s2;
		SimSet(out s);
		while (la.kind == 20 || la.kind == 21) {
			if (la.kind == 20) {
				Get();
				SimSet(out s2);
				s.Or(s2);
			} else {
				Get();
				SimSet(out s2);
				Sets.Subtract(s, s2);
			}
		}
	}

	static void AttrDecl(Symbol sym) {
		if (la.kind == 27) {
			Get();
			int beg = la.pos; int col = la.col;
			while (StartOf(9)) {
				if (StartOf(10)) {
					Get();
				} else {
					Get();
					SemErr("bad string in attributes");
				}
			}
			Expect(28);
			if (token.pos > beg)
			  sym.attrPos = new Position(beg, token.pos - beg, col);
		} else if (la.kind == 29) {
			Get();
			int beg = la.pos; int col = la.col;
			while (StartOf(11)) {
				if (StartOf(12)) {
					Get();
				} else {
					Get();
					SemErr("bad string in attributes");
				}
			}
			Expect(30);
			if (token.pos > beg)
			  sym.attrPos = new Position(beg, token.pos - beg, col);
		} else SynErr(49);
	}

	static void SemText(out Position pos) {
		Expect(40);
		int beg = la.pos; int col = la.col;
		while (StartOf(13)) {
			if (StartOf(14)) {
				Get();
			} else if (la.kind == 4) {
				Get();
				SemErr("bad string in semantic action");
			} else {
				Get();
				SemErr("missing end of previous semantic action");
			}
		}
		Expect(41);
		pos = new Position(beg, token.pos - beg, col);
	}

	static void Expression(out Graph g) {
		Graph g2;
		Term(out g);
		bool first = true;
		while (WeakSeparator(31, 15, 16)) {
			Term(out g2);
			if (first) { Graph.MakeFirstAlt(g); first = false; }
			Graph.MakeAlternative(g, g2);
		}
	}

	static void SimSet(out BitArray s) {
		int n1 = 0, n2 = 0;
		string name;
		s = new BitArray(CharClass.charSetSize);
		int max = CharClass.charSetSize;
		if (la.kind == 1) {
			Get();
			CharClass c = CharClass.Find(token.val);
			if (c == null) SemError("undefined name"); else s.Or(c.set);
		} else if (la.kind == 3) {
			String(out name);
			if (StartOf(17)) {
				foreach (char ch in name)
				  if (DFA.ignoreCase) s[char.ToLower(ch)] = true;
				  else s[ch] = true;
			} else if (la.kind == 22) {
				if (name.Length != 1 || name[0] > max-1)
				  SemError("unacceptable character value");
				else n1 = name[0] % max;
				if (DFA.ignoreCase && (char)n1 >= 'A' && (char)n1 <= 'Z') n1 += 32;
				Get();
				if (la.kind == 3) {
					String(out name);
					if (name.Length != 1 || name[0] > max-1)
					  SemError("unacceptable character value");
					else n2 = name[0] % max;
					if (DFA.ignoreCase && (char)n2 >= 'A' && (char)n2 <= 'Z') n2 += 32;
				} else if (la.kind == 24) {
					SingleChar(out n2, max);
				} else SynErr(50);
				for (int i = n1; i <= n2; i++) s[i] = true;
			} else SynErr(51);
		} else if (la.kind == 24) {
			SingleChar(out n1, max);
			s[n1] = true;
			if (la.kind == 22) {
				Get();
				if (la.kind == 3) {
					String(out name);
					if (name.Length != 1 || name[0] > max-1)
					  SemError("unacceptable character value");
					else n2 = name[0] % max;
					if (DFA.ignoreCase && (char)n2 >= 'A' && (char)n2 <= 'Z') n2 += 32;
				} else if (la.kind == 24) {
					SingleChar(out n2, max);
				} else SynErr(52);
				for (int i = n1; i <= n2; i++) s[i] = true;
			}
		} else if (la.kind == 23) {
			Get();
			s = new BitArray(CharClass.charSetSize, true);
		} else SynErr(53);
	}

	static void String(out string name) {
		Expect(3);
		name = token.val;
		name = DFA.Unescape(name.Substring(1, name.Length-2));
	}

	static void SingleChar(out int n, int max) {
		n = 0;
		Expect(24);
		Expect(25);
		Expect(2);
		n = Convert.ToInt32(token.val);
		if (n > max - 1)
		  SemError("unacceptable character value");
		if (DFA.ignoreCase && (char)n >= 'A' && (char)n <= 'Z') n += 32;
		n %= max;
		Expect(26);
	}

	static void Sym(out string name, out int kind) {
		name = "???"; kind = id;
		if (la.kind == 1) {
			Get();
			kind = id; name = token.val;
		} else if (la.kind == 3) {
			Get();
			kind = str;
			name = "\"" + token.val.Substring(1, token.val.Length-2) + "\"";
			if (DFA.ignoreCase) name = name.ToLower();
			if (name.IndexOf(' ') >= 0)
			  SemErr("literal tokens must not contain blanks");
		} else SynErr(54);
	}

	static void Term(out Graph g) {
		Graph g2; Node rslv = null; g = null;
		if (StartOf(18)) {
			if (la.kind == 38) {
				rslv = new Node(Node.rslv, null, la.line);
				Resolver(out rslv.pos);
				g = new Graph(rslv);
			}
			Factor(out g2);
			if (rslv != null) Graph.MakeSequence(g, g2);
			else g = g2;
			while (StartOf(19)) {
				Factor(out g2);
				Graph.MakeSequence(g, g2);
			}
		} else if (StartOf(20)) {
			g = new Graph(new Node(Node.eps, null, 0));
		} else SynErr(55);
		if (g == null) // invalid start of Term
		  g = new Graph(new Node(Node.eps, null, 0));
	}

	static void Resolver(out Position pos) {
		Expect(38);
		Expect(25);
		int beg = la.pos; int col = la.col;
		Condition();
		pos = new Position(beg, token.pos - beg, col);
	}

	static void Factor(out Graph g) {
		string name; int kind;
		Position pos;
		bool weak = false;
		g = null;
		switch (la.kind) {
		case 1: case 3: case 32: {
			if (la.kind == 32) {
				Get();
				weak = true;
			}
			Sym(out name, out kind);
			Symbol sym = Symbol.Find(name);
			if (sym == null && kind == str)
			  sym = Tab.literals[name] as Symbol;
			bool undef = sym == null;
			if (undef) {
			  if (kind == id)
			    sym = new Symbol(Node.nt, name, 0);  // forward nt
			  else if (genScanner) {
			    sym = new Symbol(Node.t, name, token.line);
			    DFA.MatchLiteral(sym.name, sym);
			  } else {  // undefined string in production
			    SemErr("undefined string in production");
			    sym = Tab.eofSy;  // dummy
			  }
			}
			int typ = sym.typ;
			if (typ != Node.t && typ != Node.nt)
			  SemErr("this symbol kind is not allowed in a production");
			if (weak)
			  if (typ == Node.t) typ = Node.wt;
			  else SemErr("only terminals may be weak");
			Node p = new Node(typ, sym, token.line);
			g = new Graph(p);
			if (la.kind == 27 || la.kind == 29) {
				Attribs(p);
				if (kind != id) SemErr("a literal must not have attributes");
			}
			if (undef)
			  sym.attrPos = p.pos;  // dummy
			else if ((p.pos == null) != (sym.attrPos == null))
			  SemErr("attribute mismatch between declaration and use of this symbol");
			break;
		}
		case 25: {
			Get();
			Expression(out g);
			Expect(26);
			break;
		}
		case 33: {
			Get();
			Expression(out g);
			Expect(34);
			Graph.MakeOption(g);
			break;
		}
		case 35: {
			Get();
			Expression(out g);
			Expect(36);
			Graph.MakeIteration(g);
			break;
		}
		case 40: {
			SemText(out pos);
			Node p = new Node(Node.sem, null, 0);
			p.pos = pos;
			g = new Graph(p);
			break;
		}
		case 23: {
			Get();
			Node p = new Node(Node.any, null, 0);  // p.set is set in Tab.SetupAnys
			g = new Graph(p);
			break;
		}
		case 37: {
			Get();
			Node p = new Node(Node.sync, null, 0);
			g = new Graph(p);
			break;
		}
		default: SynErr(56); break;
		}
		if (g == null) // invalid start of Factor
		  g = new Graph(new Node(Node.eps, null, 0));
	}

	static void Attribs(Node p) {
		if (la.kind == 27) {
			Get();
			int beg = la.pos; int col = la.col;
			while (StartOf(9)) {
				if (StartOf(10)) {
					Get();
				} else {
					Get();
					SemErr("bad string in attributes");
				}
			}
			Expect(28);
			if (token.pos > beg) p.pos = new Position(beg, token.pos - beg, col);
		} else if (la.kind == 29) {
			Get();
			int beg = la.pos; int col = la.col;
			while (StartOf(11)) {
				if (StartOf(12)) {
					Get();
				} else {
					Get();
					SemErr("bad string in attributes");
				}
			}
			Expect(30);
			if (token.pos > beg) p.pos = new Position(beg, token.pos - beg, col);
		} else SynErr(57);
	}

	static void Condition() {
		while (StartOf(21)) {
			if (la.kind == 25) {
				Get();
				Condition();
			} else {
				Get();
			}
		}
		Expect(26);
	}

	static void TokenTerm(out Graph g) {
		Graph g2;
		TokenFactor(out g);
		while (StartOf(7)) {
			TokenFactor(out g2);
			Graph.MakeSequence(g, g2);
		}
		if (la.kind == 39) {
			Get();
			Expect(25);
			TokenExpr(out g2);
			Graph.SetContextTrans(g2.l); Graph.MakeSequence(g, g2);
			Expect(26);
		}
	}

	static void TokenFactor(out Graph g) {
		string name; int kind;
		g = null;
		if (la.kind == 1 || la.kind == 3) {
			Sym(out name, out kind);
			if (kind == id) {
			  CharClass c = CharClass.Find(name);
			  if (c == null) {
			    SemErr("undefined name");
			    c = new CharClass(name, new BitArray(CharClass.charSetSize));
			  }
			  Node p = new Node(Node.clas, null, 0); p.val = c.n;
			  g = new Graph(p);
			  tokenString = noString;
			} else { // str
			  g = Graph.StrToGraph(name);
			  if (tokenString == null) tokenString = name;
			  else tokenString = noString;
			}
		} else if (la.kind == 25) {
			Get();
			TokenExpr(out g);
			Expect(26);
		} else if (la.kind == 33) {
			Get();
			TokenExpr(out g);
			Expect(34);
			Graph.MakeOption(g);
		} else if (la.kind == 35) {
			Get();
			TokenExpr(out g);
			Expect(36);
			Graph.MakeIteration(g);
		} else SynErr(58);
		if (g == null) // invalid start of TokenFactor
		  g = new Graph(new Node(Node.eps, null, 0));
	}



	public static void Parse() {
		la = new Token();
		la.val = "";
		Get();
		Coco();
		Expect(0);

	}

	static bool[,] set = {
		{T,T,x,T, x,x,x,x, x,T,T,T, x,x,x,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x},
		{x,T,T,T, T,T,x,x, x,x,x,x, T,T,T,x, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x},
		{T,T,x,T, x,x,x,x, x,T,T,T, x,x,x,T, T,T,T,x, x,x,x,T, x,T,x,x, x,x,x,T, T,T,x,T, x,T,T,x, T,x,x,x, x,x},
		{T,T,x,T, x,x,x,x, x,T,T,T, x,x,x,T, T,T,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x},
		{x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,x, T,x},
		{T,T,x,T, x,x,x,x, x,T,T,T, x,x,x,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x},
		{x,T,x,T, x,x,x,x, x,T,T,T, x,x,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x},
		{x,T,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,T,x,T, x,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,T, x,T,T,T, T,x,T,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,T,x, T,x,x,x, x,x,x,x, x,x},
		{x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x},
		{x,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x},
		{x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x},
		{x,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x},
		{x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x,T,T, T,x},
		{x,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, x,x,T,T, T,x},
		{x,T,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,T, x,T,T,x, x,x,x,T, T,T,T,T, T,T,T,x, T,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,T,x, T,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,T,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,T,x,x, x,x,x,x, T,T,x,T, x,T,T,x, T,x,x,x, x,x},
		{x,T,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,T,x,x, x,x,x,x, T,T,x,T, x,T,x,x, T,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,T,x, x,x,x,T, x,x,T,x, T,x,x,x, x,x,x,x, x,x},
		{x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x}

	};

} // end Parser

/* pdt - considerable extension from here on */

public class ErrorRec {
	public int line, col, num;
	public string str;
	public ErrorRec next;

	public ErrorRec(int l, int c, string s) {
		line = l; col = c; str = s; next = null;
	}
}

public class Errors {

	public static int count = 0;                                     // number of errors detected
	public static string errMsgFormat = "file {0} : ({1}, {2}) {3}"; // 0=file 1=line, 2=column, 3=text
	static string fileName = "";
	static string listName = "";
	static bool mergeErrors = false;
	static StreamWriter mergedList;

	static ErrorRec first = null, last;
	static bool eof = false;

	static string GetLine() {
		char ch, CR = '\r', LF = '\n';
		int l = 0;
		StringBuilder s = new StringBuilder();
		ch = (char) Buffer.Read();
		while (ch != Buffer.EOF && ch != CR && ch != LF) {
			s.Append(ch); l++; ch = (char) Buffer.Read();
		}
		eof = (l == 0 && ch == Buffer.EOF);
		if (ch == CR) {  // check for MS-DOS
			ch = (char) Buffer.Read();
			if (ch != LF && ch != Buffer.EOF) Buffer.Pos--;
		}
		return s.ToString();
	}

	static void Display (string s, ErrorRec e) {
		mergedList.Write("**** ");
		for (int c = 1; c < e.col; c++)
			if (s[c-1] == '\t') mergedList.Write("\t"); else mergedList.Write(" ");
		mergedList.WriteLine("^ " + e.str);
	}

	public static void Init (string fn, string dir, bool merge) {
		fileName = fn;
		listName = dir + "listing.txt";
		mergeErrors = merge;
		if (mergeErrors)
			try {
				mergedList = new StreamWriter(new FileStream(listName, FileMode.Create));
			} catch (IOException) {
				Errors.Exception("-- could not open " + listName);
			}
	}

	public static void Summarize () {
		if (mergeErrors) {
			ErrorRec cur = first;
			Buffer.Pos = 0;
			int lnr = 1;
			string s = GetLine();
			while (!eof) {
				mergedList.WriteLine("{0,4} {1}", lnr, s);
				while (cur != null && cur.line == lnr) {
					Display(s, cur); cur = cur.next;
				}
				lnr++; s = GetLine();
			}
			if (cur != null) {
				mergedList.WriteLine("{0,4}", lnr);
				while (cur != null) {
					Display(s, cur); cur = cur.next;
				}
			}
			mergedList.WriteLine();
			mergedList.WriteLine(count + " errors detected");
			mergedList.Close();
		}
		switch (count) {
			case 0 : Console.WriteLine("Parsed correctly"); break;
			case 1 : Console.WriteLine("1 error detected"); break;
			default: Console.WriteLine(count + " errors detected"); break;
		}
		if (count > 0 && mergeErrors) Console.WriteLine("see " + listName);
	}

	public static void StoreError (int line, int col, string s) {
		if (mergeErrors) {
			ErrorRec latest = new ErrorRec(line, col, s);
			if (first == null) first = latest; else last.next = latest;
			last = latest;
		} else Console.WriteLine(errMsgFormat, fileName, line, col, s);
	}

	public static void SynErr (int line, int col, int n) {
		string s;
		switch (n) {
			case 0: s = "EOF expected"; break;
			case 1: s = "ident expected"; break;
			case 2: s = "number expected"; break;
			case 3: s = "string expected"; break;
			case 4: s = "badString expected"; break;
			case 5: s = "\"COMPILER\" expected"; break;
			case 6: s = "\"IGNORECASE\" expected"; break;
			case 7: s = "\"CHARACTERS\" expected"; break;
			case 8: s = "\"TOKENS\" expected"; break;
			case 9: s = "\"NAMES\" expected"; break;
			case 10: s = "\"PRAGMAS\" expected"; break;
			case 11: s = "\"COMMENTS\" expected"; break;
			case 12: s = "\"FROM\" expected"; break;
			case 13: s = "\"TO\" expected"; break;
			case 14: s = "\"NESTED\" expected"; break;
			case 15: s = "\"IGNORE\" expected"; break;
			case 16: s = "\"PRODUCTIONS\" expected"; break;
			case 17: s = "\"=\" expected"; break;
			case 18: s = "\".\" expected"; break;
			case 19: s = "\"END\" expected"; break;
			case 20: s = "\"+\" expected"; break;
			case 21: s = "\"-\" expected"; break;
			case 22: s = "\"..\" expected"; break;
			case 23: s = "\"ANY\" expected"; break;
			case 24: s = "\"CHR\" expected"; break;
			case 25: s = "\"(\" expected"; break;
			case 26: s = "\")\" expected"; break;
			case 27: s = "\"<\" expected"; break;
			case 28: s = "\">\" expected"; break;
			case 29: s = "\"<.\" expected"; break;
			case 30: s = "\".>\" expected"; break;
			case 31: s = "\"|\" expected"; break;
			case 32: s = "\"WEAK\" expected"; break;
			case 33: s = "\"[\" expected"; break;
			case 34: s = "\"]\" expected"; break;
			case 35: s = "\"{\" expected"; break;
			case 36: s = "\"}\" expected"; break;
			case 37: s = "\"SYNC\" expected"; break;
			case 38: s = "\"IF\" expected"; break;
			case 39: s = "\"CONTEXT\" expected"; break;
			case 40: s = "\"(.\" expected"; break;
			case 41: s = "\".)\" expected"; break;
			case 42: s = "\"using\" expected"; break;
			case 43: s = "\";\" expected"; break;
			case 44: s = "??? expected"; break;
			case 45: s = "this symbol not expected in Coco"; break;
			case 46: s = "this symbol not expected in TokenDecl"; break;
			case 47: s = "invalid TokenDecl"; break;
			case 48: s = "invalid NameDecl"; break;
			case 49: s = "invalid AttrDecl"; break;
			case 50: s = "invalid SimSet"; break;
			case 51: s = "invalid SimSet"; break;
			case 52: s = "invalid SimSet"; break;
			case 53: s = "invalid SimSet"; break;
			case 54: s = "invalid Sym"; break;
			case 55: s = "invalid Term"; break;
			case 56: s = "invalid Factor"; break;
			case 57: s = "invalid Attribs"; break;
			case 58: s = "invalid TokenFactor"; break;

			default: s = "error " + n; break;
		}
		StoreError(line, col, s);
		count++;
	}

	public static void SemErr (int line, int col, int n) {
		StoreError(line, col, ("error " + n));
		count++;
	}

	public static void Error (int line, int col, string s) {
		StoreError(line, col, s);
		count++;
	}

	public static void Warn (int line, int col, string s) {
		StoreError(line, col, s);
	}

	public static void Exception (string s) {
		Console.WriteLine(s);
		System.Environment.Exit(1);
	}

} // end Errors

} // end namespace
